package cn.iocoder.yudao.framework.security.core.filter;

import cn.dev33.satoken.stp.StpUtil;
import cn.iocoder.yudao.framework.common.auth.LoginInfoHolder;
import cn.iocoder.yudao.framework.common.auth.LoginUser;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.slf4j.MDC;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;

/**
 * Token 过滤器，验证 token 的有效性
 * 验证通过后，获得 {@link LoginUser} 信息，并加入到 Spring Security 上下文
 *
 * @author 芋道源码
 */
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final SecurityProperties securityProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain)
            throws ServletException, IOException {
        try {
            if (!securityProperties.getPermitAllUrls().contains(request.getRequestURI())) {
                if (!StpUtil.isLogin()) {
                    ServletUtils.writeJSON(response, CommonResult.error(UNAUTHORIZED));
                    return;
                } else {
                    LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
                    MDC.put("X", String.valueOf(loginUser.getId()));
                    WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
                    WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
                    LoginInfoHolder.setLoginUser(loginUser);
                }
            }
            // 继续过滤链
            chain.doFilter(request, response);
        } finally {
            LoginInfoHolder.clearLoginUser();
        }
    }
}
